package cn.iocoder.yudao.module.dine.print.service.core;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.business.basic.dao.query.CoreLambdaQueryWrapper;
import cn.iocoder.yudao.framework.business.basic.service.impl.AbstractService;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.common.util.spring.SpringUtils;
import cn.iocoder.yudao.framework.qrcode.pojo.QrCodeDetailType;
import cn.iocoder.yudao.framework.qrcode.util.QrCodeUtils;
import cn.iocoder.yudao.framework.thirdparty.feieyun.FeiSDK;
import cn.iocoder.yudao.framework.util.TransactionUtils;
import cn.iocoder.yudao.module.api.trade.order.TradeOrderApi;
import cn.iocoder.yudao.module.api.trade.order.dto.TradeOrderItemRespDTO;
import cn.iocoder.yudao.module.api.trade.order.dto.TradeOrderRespDTO;
import cn.iocoder.yudao.module.dine.print.convert.DinePrintRecordConvert;
import cn.iocoder.yudao.module.dine.print.dao.DinePrintRecordMapper;
import cn.iocoder.yudao.module.dine.print.mq.DinePrintProducer;
import cn.iocoder.yudao.module.dine.print.pojo.po.DinePrintConfig;
import cn.iocoder.yudao.module.dine.print.pojo.po.DinePrintRecord;
import cn.iocoder.yudao.module.dine.print.pojo.vo.DinePrintRecordVO;
import jakarta.annotation.Nullable;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Set;

import static cn.iocoder.yudao.module.api.dine.ConfigConstants.PRINT_ORDER_SN_MOCK_PREFIX;

/**
 * <pre>
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 * 服务
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 * </pre>
 *
 * @author 山野羡民（1032694760@qq.com）
 * @since 2025/08/22
 */
@Slf4j
@Service
public class CoreDinePrintRecordService extends AbstractService<DinePrintRecord, DinePrintRecordVO> {
    @Resource
    private DinePrintRecordMapper dinePrintRecordMapper;

    @Resource
    private DinePrintProducer dinePrintProducer;

    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private TradeOrderApi tradeOrderApi;

    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private CoreDinePrintConfigService coreDinePrintConfigService;

    @Override
    public DinePrintRecordMapper getInjectedMapper() {
        return dinePrintRecordMapper;
    }

    @Override
    public DinePrintRecordVO convertToViewObject(DinePrintRecord entity) {
        return DinePrintRecordConvert.INSTANCE.toViewObject(entity);
    }

    @Transactional(rollbackFor = Exception.class)
    public void requestPrintReceipt(final TradeOrderRespDTO order) {
        log.debug("[requestPrintReceipt][请求打印点餐订单的小票({})，若打印成功则自动接单]", order.getNo());
        DinePrintConfig printConfig = coreDinePrintConfigService.getOrCreate(order.getShopId());
        final String sn = printConfig.getPrinterSn();
        if (StrUtil.isBlank(sn)) {
            log.warn("[requestPrintReceipt][请求打印点餐订单的小票({})被忽略，店铺({})的打印机标识为空]", order.getNo(), order.getShopId());
            return;
        }
        QrCodeDetailType qrCodeDetailType = new QrCodeDetailType();
        qrCodeDetailType.setTradeOrderId(order.getId());
        String qrcodeUrl = QrCodeUtils.buildUrl(qrCodeDetailType);
        List<TradeOrderItemRespDTO> orderItems = tradeOrderApi.getOrderItemsByOrderId(order.getId());
        String typeName = order.getReserveDate() != null ? "外卖(预约)" : "外卖";
        StringBuilder stringBuilder;
        stringBuilder = new StringBuilder("<CB>%s %s小票</CB><BR>\n".formatted(printConfig.getPrinterName(), typeName));
        stringBuilder.append("名称　       　　　　     单价/数量<BR>\n");
        stringBuilder.append("--------------------------------<BR>\n");
        for (TradeOrderItemRespDTO orderItem : orderItems) {
            stringBuilder.append(StrUtil.padAfter(orderItem.getSpuName(), 17, " "));
            stringBuilder.append(StrUtil.padPre(MoneyUtils.fenToYuanStr(orderItem.getPrice()), 6, " "));
            stringBuilder.append("元/");
            stringBuilder.append(orderItem.getCount() * orderItem.getUnitValue());
            stringBuilder.append(orderItem.getUnitName());
            stringBuilder.append("<BR>\n");
        }
        stringBuilder.append("备注：%s<BR>\n".formatted(StrUtil.isBlank(order.getUserRemark()) ? "无" : order.getUserRemark()));
        stringBuilder.append("--------------------------------<BR>\n");
        stringBuilder.append("配送费：%s元<BR>\n".formatted(MoneyUtils.fenToYuanStr(order.getDeliveryPrice())));
        stringBuilder.append("合计：%s元<BR>\n".formatted(MoneyUtils.fenToYuanStr(order.getTotalPrice() + order.getDeliveryPrice())));
        stringBuilder.append("实付款：%s元<BR>\n".formatted(MoneyUtils.fenToYuanStr(order.getPayPrice())));
        stringBuilder.append("用餐人数：%s人<BR>\n".formatted(order.getDinePeoples()));
        stringBuilder.append("送餐地址：%s<BR>\n".formatted(order.getReceiverDetailAddress()));
        stringBuilder.append("联系电话：%s<BR>\n".formatted(order.getReceiverMobile()));
        stringBuilder.append("下单时间：%s<BR>\n".formatted(order.getCreateTime()));
        if (order.getReserveDate() != null) {
            stringBuilder.append("预约时间：%s%s<BR>\n".formatted(order.getReserveDate(), order.getReservePeriod()));
        }
        stringBuilder.append("<QR>%s</QR>\n".formatted(qrcodeUrl));
        stringBuilder.append("<CUT>");
        final DinePrintRecord entity = new DinePrintRecord();
        entity.setShopId(order.getShopId());
        entity.setTradeNo(order.getNo());
        entity.setOrderSn("");
        entity.setPrinterSn(printConfig.getPrinterSn());
        entity.setContent(stringBuilder.toString());
        entity.setSuccess(false);
        entity.setNotifyData(null);
        dinePrintRecordMapper.insert(entity);
        String finalContent = stringBuilder.toString();
        TransactionUtils.afterCommit(() -> {
            try {
                final String callbackUrl = "https://api.mdycjt.com/app-api/dine/printer/notify";
                String orderSn = PRINT_ORDER_SN_MOCK_PREFIX + RandomUtil.randomNumbers(10);
                if (!SpringUtils.isLocalhostEnvironment()) {
                    orderSn = FeiSDK.printMsg(sn, finalContent, callbackUrl);
                } else {
                    log.warn("[requestPrintReceipt][请求打印点餐订单的小票({})成功]，本机环境不发起真实打印请求，可以模拟回调：{}?orderId={}", order.getNo(), callbackUrl, orderSn);
                }
                DinePrintRecord updateObj = new DinePrintRecord();
                updateObj.setId(entity.getId());
                updateObj.setOrderSn(orderSn);
                dinePrintRecordMapper.updateById(updateObj);
                log.info("[requestPrintReceipt][请求打印点餐订单的小票({})成功]，打印序列号为({})", order.getNo(), orderSn);
            } catch (Exception e) {
                log.error("[requestPrintReceipt][请求打印点餐订单的小票({})失败]", order.getNo(), e);
            }
            return null;
        });
    }

    @Transactional(rollbackFor = Exception.class)
    public void update(String orderSn, boolean success, @Nullable String notifyData) {
        if (!success) {
            log.warn("[update][打印序列号({})未打印成功，忽略打印失败的情况]", orderSn);
            return;
        }
        CoreLambdaQueryWrapper<DinePrintRecord> queryWrapper = new CoreLambdaQueryWrapper<>();
        queryWrapper.eq(DinePrintRecord::getOrderSn, orderSn);
        DinePrintRecord record = dinePrintRecordMapper.selectOne(queryWrapper);
        if (record == null) {
            log.warn("[update][打印序列号({})对应的订单不存在]", orderSn);
            return;
        }
        DinePrintRecord updateObj = new DinePrintRecord();
        updateObj.setId(record.getId());
        updateObj.setSuccess(true);
        if (notifyData != null) {
            updateObj.setNotifyData(notifyData);
        }
        dinePrintRecordMapper.updateById(updateObj);
        dinePrintProducer.sendDinePrintedMessage(record.getTradeNo());
    }

    public List<DinePrintRecord> getListByTradeNos(Set<String> tradeNos) {
        return dinePrintRecordMapper.selectList(DinePrintRecord::getTradeNo, tradeNos);
    }

}
